iT邦幫忙

2025 iThome 鐵人賽

DAY 1
0
Software Development

Python pytest TDD 實戰:從零開始的測試驅動開發系列 第 1

Day 01 - 環境設置與第一個測試 🚀

  • 分享至 

  • xImage
  •  

今天要做什麼?

歡迎來到「Python pytest TDD 實戰:從零開始的測試驅動開發」系列!

想像一下,你是一位新手開發者,剛加入一個重視程式品質的團隊。主管交給你第一個任務:「我們要建立一個 Python 專案,而且要從第一天就導入測試文化。」聽起來很有挑戰性?別擔心,讓我們從最基礎的開始,一步步建立起 TDD 的基礎。

今天是我們 TDD 旅程的第一天,我們要設置 Python + pytest 的開發環境,並寫下第一個測試。就像學開車一樣,我們先在安全的練習場地熟悉基本操作。

學習目標

今天結束後,你將學會:

  • 建立 Python + pytest 開發環境
  • 了解 pytest 的基本配置
  • 寫出第一個單元測試
  • 體驗測試失敗到通過的完整過程
  • 理解測試檔案的組織結構

TDD 學習地圖

第一階段:打好基礎(Day 1-10)
├── Day 01 - 環境設置與第一個測試 ★ 今天在這裡
├── ...
└── (更多精彩內容待續)

建立專案環境 🏗️

首先建立一個全新的 Python 專案:

mkdir python-tdd-demo
cd python-tdd-demo

建立虛擬環境:

# macOS/Linux
python -m venv venv
source venv/bin/activate

# Windows
python -m venv venv
venv\Scripts\activate

安裝測試套件

安裝 pytest 和相關套件:

pip install pytest pytest-cov

配置 pytest

建立 pytest.ini 配置檔:

[tool:pytest]
testpaths = tests
python_files = test_*.py
python_functions = test_*
addopts = 
    -v
    --tb=short
    --strict-markers
    --disable-warnings

建立 requirements-dev.txt

pytest>=7.0.0
pytest-cov>=4.0.0

建立專案結構

建立基本的專案結構:

python-tdd-demo/
├── src/
│   └── __init__.py
├── tests/
│   └── __init__.py
├── pytest.ini
├── requirements-dev.txt
└── README.md

建立空的 src/__init__.pytests/__init__.py

mkdir src tests
touch src/__init__.py tests/__init__.py

第一個測試:計算機函數 🧮

讓我們從最簡單的例子開始 - 計算機函數。

建立 tests/day01/test_calculator.py

# 先寫測試,這時 calculator 模組還不存在
from src.calculator import add

def test_adds_two_numbers_correctly():
    result = add(2, 3)
    assert result == 5

執行測試(紅燈階段)🔴

pytest

你會看到測試失敗的訊息,因為 calculator 模組還不存在。這就是 TDD 的「紅燈」階段 - 先寫測試,看它失敗。

實作程式碼(綠燈階段)🟢

建立 src/calculator.py

def add(a: int, b: int) -> int:
    return a + b

再次執行測試:

pytest

現在測試應該通過了!這就是「綠燈」階段。

新增更多測試案例

更新 tests/day01/test_calculator.py

import pytest
from src.calculator import add, subtract, multiply, divide

def test_adds_two_numbers_correctly():
    result = add(2, 3)
    assert result == 5

def test_adds_negative_numbers_correctly():
    result = add(-2, 3)
    assert result == 1

def test_subtracts_two_numbers_correctly():
    result = subtract(5, 3)
    assert result == 2

def test_multiplies_two_numbers_correctly():
    result = multiply(4, 3)
    assert result == 12

def test_divides_two_numbers_correctly():
    result = divide(10, 2)
    assert result == 5

def test_handles_division_by_zero():
    with pytest.raises(ZeroDivisionError):
        divide(10, 0)

完整實作 calculator

更新 src/calculator.py

def add(a: int, b: int) -> int:
    return a + b

def subtract(a: int, b: int) -> int:
    return a - b

def multiply(a: int, b: int) -> int:
    return a * b

def divide(a: int, b: int) -> float:
    if b == 0:
        raise ZeroDivisionError("Cannot divide by zero")
    return a / b

執行測試確認

pytest tests/

所有測試都應該通過!你也可以執行特定測試檔案:

pytest tests/day01/test_calculator.py

使用函數風格的測試

pytest 支援函數風格的測試,這更符合 Python 的簡潔哲學。所有測試都是簡單的函數,使用 assert 進行驗證。

美化測試輸出

pytest 提供多種輸出選項:

# 詳細輸出
pytest -v

# 顯示覆蓋率
pytest --cov=src

# 產生 HTML 覆蓋率報告
pytest --cov=src --cov-report=html

# 顯示最慢的測試
pytest --durations=10

# 只執行失敗的測試
pytest --lf

# 顯示本地變數值(除錯用)
pytest -l

# 停在第一個失敗
pytest -x

常見錯誤與解決方法 ⚠️

在開始 TDD 的第一天,你可能會遇到一些問題:

ImportError: No module named 'src'

如果遇到模組匯入錯誤,確保:

  • 你在專案根目錄執行測試
  • src/__init__.py 檔案存在
  • 虛擬環境已經啟動

測試找不到

如果 pytest 找不到測試:

  • 確認測試檔案以 test_ 開頭
  • 確認測試函數以 test_ 開頭
  • 檢查 pytest.ini 配置是否正確

今天學到什麼?

1. 測試驅動開發的基本循環

  • 紅燈:先寫測試,看它失敗
  • 綠燈:寫最少的程式碼讓測試通過
  • 重構:改善程式碼品質

2. pytest 基礎概念

  • assert: 簡單直觀的斷言語法
  • pytest.raises: 測試異常處理
  • 函數風格測試:簡潔的測試寫法

3. 測試檔案組織

  • 測試檔案放在 tests/ 目錄
  • 按天數組織學習內容(如 tests/day01/test_calculator.py
  • 使用 test_ 前綴命名測試檔案和測試函數
  • 測試檔案結構應該反映被測試的程式碼結構

4. Python 類型提示的價值

  • 使用 -> 標註回傳型別
  • 參數型別標註提高可讀性
  • IDE 提供更好的自動完成

測試組織最佳實踐

每個測試都應該遵循 AAA 模式:

  1. Arrange(準備):設定測試資料和環境
  2. Act(執行):執行要測試的功能
  3. Assert(驗證):檢查結果是否符合預期

小挑戰 🎯

試著為計算機新增以下功能:

  1. 餘數運算:實作 modulo(a, b) 函數
  2. 次方運算:實作 power(base, exponent) 函數
  3. 錯誤處理:當輸入不是數字時該如何處理?

💡 提示:記得先寫測試再實作功能!

今天的收穫

今天我們完成了 TDD 學習旅程的第一步!透過建立 Python + pytest 環境,我們學會了:

  • 如何設置乾淨的測試環境
  • TDD 的基本循環:紅燈 → 綠燈 → 重構
  • pytest 簡潔直觀的測試語法
  • Python 類型提示在測試中的價值

總結

今天我們成功建立了 Python + pytest 的測試環境,並完成了第一個單元測試。雖然例子很簡單,但我們已經體驗了完整的 TDD 流程:

  1. 先寫測試(紅燈)
  2. 實作功能(綠燈)
  3. 確保測試通過

記住,TDD 不只是一種測試技術,更是一種設計思維。透過先寫測試,我們被迫思考程式的介面和行為,這能幫助我們寫出更好的程式碼。

明天我們將深入了解斷言函數的威力,學習如何寫出更有表達力的測試。準備好了嗎?繼續加油! 💪


下一篇
Day 02 - 認識斷言(Assertions) 🚀
系列文
Python pytest TDD 實戰:從零開始的測試驅動開發8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言